﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.IO.Ports;
using System.Timers;
using System.IO;

namespace ScanDevConsole
{


    public partial class MainForm : Form
    {
        public delegate void ToastInfoDelegate(string info, System.Drawing.Brush color);    //打印信息的函数指针类型
        public ToastInfoDelegate toastInfo;     //打印信息的函数指针
        private System.Collections.Generic.List<System.Drawing.Brush> infoBrush;    //信息 颜色画刷
        private object infoListLocker;  //访问信息 锁

        private Thread commthread;   //串口线程
        private ScanDeviceProcess scandev;

        private System.Timers.Timer refreshDispTimer;   //用于刷新设备信息的显示的定时器
        private ElapsedEventHandler refreshDispHandler;

        public MainForm()
        {
            InitializeComponent();
            this.Text = "扫描设备控制台 V1.0";
            this.comboBox_SerialPort.SelectedIndex = 0;
            this.comboBox_Baudrate.SelectedIndex = 2;
            this.tabControlMain.SelectedIndex = 0;
            this.numUpDown_SlaveID.Value = 1;
            this.comboBox_ProbeType.SelectedIndex = 0;
            this.comboBox_ScanShape.SelectedIndex = 0;
            this.lampProbeType.namesOnOff = new string[] { "MEMS", "振镜" };
            this.lampProbeType.isOn = false;
            //this.lampProbeType.isOn = true;
            this.btnRedLaser.ToggledEvent += new EventHandler(onBtnRedLightToggled);
            refreshAvailableSerialPortName();


            infoListLocker = new object();
            infoBrush = new System.Collections.Generic.List<System.Drawing.Brush>();
            toastInfo = this.pushInfo;


            scandev = new ScanDeviceProcess();
            scandev.toastInfoDel = pushInfo;

            refreshDispTimer = new System.Timers.Timer();
            refreshDispTimer.AutoReset = true;
            refreshDispTimer.Interval = 100;    //每100ms超时
            refreshDispHandler = new System.Timers.ElapsedEventHandler(onRefreshDispTimeOut);
            refreshDispTimer.Elapsed += refreshDispHandler;

        }

        private void MainForm_Resize(object sender, EventArgs e)    //窗口改变时 tabcrontal控件需要这样才会重新调整大小
        {
            tabControlMain.Refresh();
        }

        private void pushInfo(string info, System.Drawing.Brush color)  //向 信息组件 压入信息
        {
            if (this.InvokeRequired)
            {
                if (info == null)
                {
                    Action a = new Action(() =>
                    {
                        lock (infoListLocker)
                        {
                            this.listBoxInfo.Items.Clear();
                            infoBrush.Clear();
                        }
                    }
                    );
                    BeginInvoke(a);
                }
                else
                {
                    Action<string, Brush> a = new Action<string, Brush>(updateInfo);
                    BeginInvoke(a, DateTime.Now.ToString() + ": " + info, color);
                }
            }
            else
            {
                updateInfo(DateTime.Now.ToString() + ": " + info, color);
            }
        }

        private void updateInfo(string info, Brush color)    //在信息组件中添加一行字符串
        {
            lock (infoListLocker)
            {
                if (this.listBoxInfo.Items.Count > 200)
                {
                    infoBrush.Clear();
                    this.listBoxInfo.Items.Clear();
                }
                infoBrush.Insert(0, color);
                listBoxInfo.Items.Insert(0, info);
                listBoxInfo.SelectedIndex = 0;
                listBoxInfo.SelectedIndex = -1;
            }

        }

        private void btnClearInfo_Click(object sender, EventArgs e) //清除信息按钮 按下
        {
            lock (infoListLocker)
            {
                this.listBoxInfo.Items.Clear();
                infoBrush.Clear();
            }
        }

        private void listBoxInfo_DrawItem(object sender, DrawItemEventArgs e)
        {
            lock (infoListLocker)
            {
                if (e.Index >= 0 && infoBrush.Count > 0)
                {
                    e.DrawBackground();
                    Brush mybsh = Brushes.Black;
                    if (infoBrush.Count > e.Index) mybsh = infoBrush[e.Index];
                    e.DrawFocusRectangle();
                    //文本   
                    e.Graphics.DrawString(listBoxInfo.Items[e.Index].ToString(), e.Font, mybsh, e.Bounds, StringFormat.GenericDefault);
                }

            }

        }

        private void refreshAvailableSerialPortName()       //获取当前可用的串口号
        {
            
            string[] names = System.IO.Ports.SerialPort.GetPortNames();

            if (names.Length < 1) return;
            string lastname = comboBox_SerialPort.SelectedItem.ToString().ToUpper();
            int i = 0;
            foreach(string n in names)
            {
                if(n.ToUpper() == lastname)
                {
                    break;
                }
                i++;
            }

            comboBox_SerialPort.Items.Clear();
            comboBox_SerialPort.Items.AddRange(names);
            comboBox_SerialPort.SelectedIndex = i;
        }

        private void MainForm_FormClosed(object sender, FormClosedEventArgs e)  //主窗体关闭时
        {
            refreshDispTimer.Stop();
            refreshDispTimer.Elapsed -= refreshDispHandler;
            if (commthread != null)
            {
                scandev.reqQuitRun = true;
                int i = 10;
                while (commthread.IsAlive)
                {
                    Thread.Sleep(200);
                    i--;
                    if (i <= 0)
                    {
                        commthread.Abort();
                        break;
                    }
                }

                commthread = null;
                scandev.reqQuitRun = false;
            }
        }


        private void tabControlMain_SelectedIndexChanged(object sender, EventArgs e)
        {
            refreshAvailableSerialPortName();
            refreshDispTimer.Stop();
            if (commthread != null)     //请求并等待线程结束
            {
                scandev.reqQuitRun = true;
                int i = 10;
                while (commthread.IsAlive)
                {
                    Thread.Sleep(200);
                    i--;
                    if (i <= 0)
                    {
                        commthread.Abort();
                        break;
                    }
                }

                commthread = null;
                scandev.reqQuitRun = false;
            }

            if (tabControlMain.SelectedIndex != 0)      //不为第一个页面时 执行通信线程
            {
                scandev.reqQuitRun = false;
                scandev.portname = comboBox_SerialPort.SelectedItem.ToString();
                scandev.baudrate = Convert.ToInt32(comboBox_Baudrate.SelectedItem.ToString());
                scandev.slaveID = Convert.ToInt32(numUpDown_SlaveID.Value);
                commthread = new Thread(scandev.ScanDevRun);

                commthread.Start();
                refreshDispTimer.Start();
            }
        }

        private void onRefreshDispTimeOut(object source, System.Timers.ElapsedEventArgs e)         //一定时间 刷新设备信息显示
        {
            if (this.InvokeRequired)
            {
                Action ac = () =>
                {
                    if (scandev != null)
                    {
                        lampProbeType.isOn = scandev.input_ProbeType;
                        lampCapture.isOn = scandev.input_Capture;
                        lampGrabMultiFrame.isOn = scandev.input_VideoCap;
                    }
                };
                BeginInvoke(ac);
            }
            else
            {
                if (scandev != null)
                {
                    lampProbeType.isOn = scandev.input_ProbeType;
                    lampCapture.isOn = scandev.input_Capture;
                    lampGrabMultiFrame.isOn = scandev.input_VideoCap;
                }
            }
        }

        private void btnApplyScanVar_Click(object sender, EventArgs e)  //应用参数到设备
        {
            if (scandev == null) return;

            if (comboBox_ProbeType.SelectedIndex == 0)
            {
                scandev.scanParams.probeType = 1;
            }
            else
            {
                scandev.scanParams.probeType = 0;
            }

            if (comboBox_ScanShape.SelectedIndex == 3)
            {
                scandev.scanParams.scanShape = 255;
            }
            else if (comboBox_ScanShape.SelectedIndex == 2)
            {
                scandev.scanParams.scanShape = 2;
            }
            else if (comboBox_ScanShape.SelectedIndex == 1)
            {
                scandev.scanParams.scanShape = 1;
            }
            else
            {
                scandev.scanParams.scanShape = 0;
            }

            scandev.scanParams.x_stepPerRange = Convert.ToInt32(numXStep.Value);
            scandev.scanParams.y_stepPerRange = Convert.ToInt32(numYStep.Value);
            scandev.scanParams.x_freq_div = Convert.ToUInt32(numXPreDiv.Value);
            scandev.scanParams.y_freq_div = 1;// Convert.ToUInt32(numXPreDiv.Value);

            scandev.scanParams.wave_phase_shift = Convert.ToInt32(numSyncOffset.Value);

            scandev.scanParams.y_AmpScale = Convert.ToSingle(numYVscale.Value);

            float dt = Convert.ToSingle(numXAxisV.Value);
            if (scandev.scanParams.probeType == 0 && dt < 0)
            {
                dt = -dt;
            }
            scandev.scanParams.x_start_v = -dt;
            scandev.scanParams.x_end_v = dt;

            dt = Convert.ToSingle(numYAxisV.Value);
            if (scandev.scanParams.probeType == 0 && dt < 0)
            {
                dt = -dt;
            }
            scandev.scanParams.y_start_v = -dt;
            scandev.scanParams.y_end_v = dt;

            if (scandev.scanParams.probeType == 0)
            {
                scandev.scanParams.x_start_v = 0;
                scandev.scanParams.y_start_v = 0;
            }

            scandev.cmdApplyScanParams = true;

            if (scandev.scanParams.scanShape == 255 && scandev.scanParams.probeType == 1)
            {
                //利萨如
                dt = Convert.ToSingle(numLissajousAX.Value);
                if (dt < 0) dt = -dt;
                scandev.lissajousParam.Amp_x = dt;

                dt = Convert.ToSingle(numLissajousAY.Value);
                if (dt < 0) dt = -dt;
                scandev.lissajousParam.Amp_y = dt;

                dt = Convert.ToSingle(numLissajousFreqX.Value);
                if (dt < 0) dt = -dt;
                scandev.lissajousParam.Freq_x = dt;

                dt = Convert.ToSingle(numLissajousFreqY.Value);
                if (dt < 0) dt = -dt;
                scandev.lissajousParam.Freq_y = dt;

                dt = Convert.ToSingle(numLissajousPhaseX.Value);
                if (dt < 0) dt = -dt;
                scandev.lissajousParam.Phase_x = dt;

                dt = Convert.ToSingle(numLissajousPhaseY.Value);
                if (dt < 0) dt = -dt;
                scandev.lissajousParam.Phase_y = dt;

                scandev.cmdApplyLissajousParams = true;
            }
            
        }

        private void btnApplyToDev2_Click(object sender, EventArgs e)
        {
            btnApplyScanVar_Click(sender, e);
        }

        private void onBtnRedLightToggled(object sender, EventArgs e)       //辅助红光切换按钮 切换
        {
            if (scandev == null) return;

            scandev.redLightOn = btnRedLaser.isOn;
            scandev.cmdRedLight = true;
        }

        private void btnInteralTrig_Click(object sender, EventArgs e)   //启动内部触发 按钮点击
        {
            if (scandev == null) return;

            scandev.cmdSetInteralTrig = true;
        }

        private void btnSendWaveFile_Click(object sender, EventArgs e)  //写入波形数据按钮 点击
        {
            if (scandev == null) return;
            
            //获取打开文件名
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "打开波形数据CSV文件";
            dlg.Filter = "CSV文件（*.csv）|*.csv|所有文件(*.*) |*.*";
            dlg.CheckFileExists = true;

            if (dlg.ShowDialog() != DialogResult.OK) return;

            string filename = System.IO.Path.GetFullPath(dlg.FileName);                             //绝对路径

            if (filename == null) return;

            FileStream fs = null;
            try
            {
                fs = new FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read);
            }
            catch
            {
            }
            if (fs == null)
            {
                MessageBox.Show("打开文件失败！", "打开波形数据CSV文件",
                    MessageBoxButtons.OK,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button1
                );
                return;
            }
            
            StreamReader sr = null;
            try
            {
                sr = new StreamReader(fs, Encoding.ASCII);
            }
            catch
            {
            }
            if (sr == null)
            {
                MessageBox.Show("打开文件失败！", "打开波形数据CSV文件",
                    MessageBoxButtons.OK,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button1
                );
                return;
            }

            //读取文件数据

            bool validFormat = true;    //文件格式是否有效

            string strLine = "";    //记录每次读取的一行记录

            List<double> x_org_data = new List<double>();   //x轴波形原始数据
            List<double> y_org_data = new List<double>();   //y轴波形原始数据
            double x_max = 0, x_min = 0, x_range;   //x轴最大值 最小值 数据值范围
            double y_max = 0, y_min = 0, y_range;   //y轴最大值 最小值 数据值范围

            while ((strLine = sr.ReadLine()) != null)
            {
                //Debug.WriteLine(strLine);
                string[] fieldStr = strLine.Split(',');
                if (fieldStr.Length < 2)
                {
                    validFormat = false;
                    break;
                }


                double dt = 0;
                if (double.TryParse(fieldStr[0], out dt))
                {
                    if (x_org_data.Count() == 0)
                    {
                        x_max = dt;
                        x_min = dt;
                    }
                    else
                    {
                        if (dt > x_max) x_max = dt;
                        if (dt < x_min) x_min = dt;
                    }
                    x_org_data.Add(dt);
                }
                else
                {
                    validFormat = false;
                    break;
                }
                dt = 0;
                if (double.TryParse(fieldStr[1], out dt))
                {
                    if (y_org_data.Count() == 0)
                    {
                        y_max = dt;
                        y_min = dt;
                    }
                    else
                    {
                        if (dt > y_max) y_max = dt;
                        if (dt < y_min) y_min = dt;
                    }
                    y_org_data.Add(dt);
                }
                else
                {
                    validFormat = false;
                    break;
                }


            }

            if (x_org_data.Count() < 2 || y_org_data.Count() < 2) validFormat = false;

            x_range = x_max - x_min;
            y_range = y_max - y_min;

            if (!validFormat)
            {
                MessageBox.Show("无效的文件格式！", "打开波形数据CSV文件",
                    MessageBoxButtons.OK,
                MessageBoxIcon.Warning,
                MessageBoxDefaultButton.Button1
                );
                return;
            }

            sr.Close();
            fs.Close();
            sr = null;
            fs = null;

            //生成归一化数据
            double[] x_n_data = new double[4 * 1024];
            double[] y_n_data = new double[4 * 1024];

            for (int i = 0; i < 4 * 1024; ++i)
            {
                double dt = 0, dt1 = 0, delta;
                int offset;

                //计算x轴
                dt = i;
                dt = dt / 4095;
                dt = dt * (x_org_data.Count() - 1);
                offset = (int)(dt);
                delta = dt - offset;
                if (offset < 0) offset = 0;
                if (offset >= x_org_data.Count()) offset = x_org_data.Count() - 1;

                dt = x_org_data[offset];
                if (offset < x_org_data.Count() - 1)
                {
                    dt1 = x_org_data[offset + 1];
                }
                else
                {
                    dt1 = dt;
                }

                dt = dt + (dt1 - dt) * delta;
                dt = dt - x_min;
                dt = dt / x_range;
                if (dt < 0) dt = 0;
                if (dt > 1) dt = 1;
                if (double.IsNaN(dt)) dt = 1;
                x_n_data[i] = dt;

                //计算y轴
                dt = i;
                dt = dt / 4095;
                dt = dt * (y_org_data.Count() - 1);
                offset = (int)(dt);
                delta = dt - offset;
                if (offset < 0) offset = 0;
                if (offset >= y_org_data.Count()) offset = y_org_data.Count() - 1;

                dt = y_org_data[offset];
                if (offset < y_org_data.Count() - 1)
                {
                    dt1 = y_org_data[offset + 1];
                }
                else
                {
                    dt1 = dt;
                }

                dt = dt + (dt1 - dt) * delta;
                dt = dt - y_min;
                dt = dt / y_range;
                if (dt < 0) dt = 0;
                if (dt > 1) dt = 1;
                if (double.IsNaN(dt)) dt = 1;
                y_n_data[i] = dt;
            }

            scandev.memsWaveData = new UInt16[8 * 1024];
            for (int i = 0; i < 4 * 1024; ++i)
            {
                UInt16 ut = (UInt16)(x_n_data[i] * 20000);
                if (ut > 20000) ut = 20000;
                scandev.memsWaveData[i] = ut;
            }

            for (int i = 0; i < 4 * 1024; ++i)
            {
                UInt16 ut = (UInt16)(y_n_data[i] * 20000);
                if (ut > 20000) ut = 20000;
                scandev.memsWaveData[i + 4096] = ut;
            }

            scandev.cmdUpdateWaveData = true;
        }

        private void btnReadWaveData_Click(object sender, EventArgs e)  //当读取波形数据按钮 点击时 读取设备波形数据 保存为CSV文件
        {
            if (scandev == null) return;

            //获取保存文件名
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Title = "选择保存波形数据CSV文件";
            dlg.Filter = "CSV文件（*.csv）|*.csv";

            if (dlg.ShowDialog() != DialogResult.OK) return;

            string filename = System.IO.Path.GetFullPath(dlg.FileName);                             //绝对路径

            if (filename == null) return;

            scandev.saveCSVFileName = filename;
            scandev.cmdReadWave = true;
        }

    }//窗体
}
